package com.share.tool.devops.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.share.tool.devops.model.es.EsLogPage;
import com.share.tool.devops.model.es.EsLogReq;
import com.share.tool.devops.service.EsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.list.TreeList;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Slf4j
@Service
public class EsServiceImpl implements EsService {
    private final String DEFAULT_DOC = "_doc";
    private final Integer GROUP_SIZE = 10000;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public List<Object> listIndex() {
        List<Object> reList = new LinkedList<>();

        Map<String, Object> tmpMap = new TreeMap<>();
        RestClient lowLevelClient = client.getLowLevelClient();
        InputStream is = null;
        try {
            Request request = new Request("GET", "/_cat/indices");
            Response response = lowLevelClient.performRequest(request);

            is = response.getEntity().getContent();
            ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();

            int len;
            byte[] temp = new byte[1024];
            while ((len = is.read(temp)) != -1) {
                outBuffer.write(temp, 0, len);
            }

            String s = outBuffer.toString();
            String[] split = s.split("\n");
            for (String line : split) {
                if (StringUtils.isBlank(line)) {
                    continue;
                }
                String name = line.substring(10, 43).trim();
                String count = line.substring(70, 79).trim();

                //索引的名字
                if (name.contains("risk")) {
                    tmpMap.put(name, count);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return reList;
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    return reList;
                }
            }
        }


        //重新排序
        String first_key = "risk_log";
        for (String key : tmpMap.keySet()) {
            JSONObject obj = new JSONObject();
            obj.put(key, tmpMap.get(key));

            if (first_key.equals(key)) {
                continue;
            } else {
                reList.add(0, obj);
            }
        }


        if (tmpMap.get(first_key) != null) {
            reList.add(0, tmpMap.get(first_key));
        }

        return reList;
    }


    @Override
    public List<Object> listApplicationName(EsLogReq req) {
        //1.构建请求发起对象
        SearchRequest searchRequest = new SearchRequest(req.getIndex());
        // searchRequest.searchType(DEFAULT_DOC); 不需要设置

        //2.构建查询条件
        SearchSourceBuilder sourceBuilder = addCondition(req);
        sourceBuilder.size(0);//无需返回hits

        //3.分组聚合
        String field1 = "application_name.keyword";
        String key1 = "group_application_name";
        AbstractAggregationBuilder count = AggregationBuilders.count("count").field(field1);
        TermsAggregationBuilder group = AggregationBuilders.terms(key1).field(field1);
        group.size(GROUP_SIZE);//设置分组最大返回的条数
        sourceBuilder.aggregation(group.subAggregation(count)); /*对application_name分组并count计数*/

        log.info("普通查询的DSL语句:" + sourceBuilder.toString());
        searchRequest.source(sourceBuilder);

        //执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }


        List<Object> reList = new TreeList();
        ParsedTerms aggregation = searchResponse.getAggregations().get(key1);
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();

            JSONObject obj = new JSONObject();
            obj.put(key, docCount);

            reList.add(obj);
        }

        return reList;
    }

    @Override
    public List<Object> listIp(EsLogReq req) {
        //1.构建请求发起对象
        SearchRequest searchRequest = new SearchRequest(req.getIndex());
        // searchRequest.searchType(DEFAULT_DOC); 不需要设置

        //2.构建查询条件
        SearchSourceBuilder sourceBuilder = addCondition(req);
        sourceBuilder.size(0);//无需返回hits

        //3.分组聚合
        String field1 = "ip.keyword";
        String key1 = "group_ip";
        AbstractAggregationBuilder count = AggregationBuilders.count("count").field(field1);
        TermsAggregationBuilder group = AggregationBuilders.terms(key1).field(field1);
        group.size(GROUP_SIZE);//设置分组最大返回的条数
        sourceBuilder.aggregation(group.subAggregation(count)); /*对ip分组并count计数*/

        log.info("普通查询的DSL语句:" + sourceBuilder.toString());
        searchRequest.source(sourceBuilder);

        //执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<Object> reList = new TreeList();
        ParsedTerms aggregation = searchResponse.getAggregations().get(key1);
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();

            JSONObject obj = new JSONObject();
            obj.put(key, docCount);

            reList.add(obj);
        }

        return reList;
    }


    @Override
    public List<Object> listApplicationNameAndIp(EsLogReq req) {
        //1.构建请求发起对象
        SearchRequest searchRequest = new SearchRequest(req.getIndex());
        // searchRequest.searchType(DEFAULT_DOC); 不需要设置

        //2.构建查询条件
        SearchSourceBuilder sourceBuilder = addCondition(req);
        sourceBuilder.size(0);//无需返回hits

        //3.分组聚合
        String field1 = "application_name.keyword";
        String key1 = "group_application_name";

        TermsAggregationBuilder group1 = AggregationBuilders.terms(key1).field(field1);

        String field2 = "ip.keyword";
        String key2 = "group_ip";
        AbstractAggregationBuilder count2 = AggregationBuilders.count("count").field(field2);
        TermsAggregationBuilder group2 = AggregationBuilders.terms(key2).field(field2);

        group1.size(GROUP_SIZE);//设置分组最大返回的条数
        group2.subAggregation(count2);
        sourceBuilder.aggregation(group1.subAggregation(group2)); /*对application_name分组并count计数*/

        log.info("普通查询的DSL语句:" + sourceBuilder.toString());
        searchRequest.source(sourceBuilder);

        //执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<Object> reList = new TreeList();
        ParsedTerms aggregation = searchResponse.getAggregations().get(key1);
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            String appkey = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            JSONObject obj = new JSONObject();

            List<String> list = new LinkedList();
            ParsedTerms aggregation1 = bucket.getAggregations().get(key2);
            for (Terms.Bucket bucket1 : aggregation1.getBuckets()) {
                String ip = bucket1.getKeyAsString();
                long ipCount = bucket1.getDocCount();
                list.add(ip + "-" + ipCount);
            }
            obj.put(appkey, list);
            reList.add(obj);
        }

        return reList;
    }


    @Override
    public List<Object> listClasspath(EsLogReq req) {
        //1.构建请求发起对象
        SearchRequest searchRequest = new SearchRequest(req.getIndex());
        // searchRequest.searchType(DEFAULT_DOC); 不需要设置

        //2.构建查询条件
        SearchSourceBuilder sourceBuilder = addCondition(req);
        sourceBuilder.size(0);//无需返回hits

        //3.分组聚合
        String field1 = "classpath.keyword";
        String key1 = "group_classpath";
        AbstractAggregationBuilder count = AggregationBuilders.count("count").field(field1);
        TermsAggregationBuilder group = AggregationBuilders.terms(key1).field(field1);
        group.size(GROUP_SIZE);//设置分组最大返回的条数
        sourceBuilder.aggregation(group.subAggregation(count)); /*对classpath分组并count计数*/

        log.info("普通查询的DSL语句:" + sourceBuilder.toString());
        searchRequest.source(sourceBuilder);

        //执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<Object> reList = new TreeList();
        ParsedTerms aggregation = searchResponse.getAggregations().get(key1);
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();

            JSONObject obj = new JSONObject();
            obj.put(key, docCount);

            reList.add(obj);
        }

        return reList;
    }

    @Override
    public EsLogPage pageList(EsLogReq req) {
        //1.构建请求发起对象
        SearchRequest searchRequest = new SearchRequest(req.getIndex());
        // searchRequest.searchType(DEFAULT_DOC); 不需要设置

        //2.构建查询条件
        SearchSourceBuilder sourceBuilder = addCondition(req);

        //指定需要返回或者排除的字段
//        String[] includes = { "id", "name"};
//        String[] excludes = {};
//        sourceBuilder.fetchSource(includes, excludes);

        //年龄倒序
        sourceBuilder.sort("timestamp", SortOrder.DESC);
        sourceBuilder.from(req.getFrom());
        sourceBuilder.size(req.getSize());

        log.info("普通查询的DSL语句:" + sourceBuilder.toString());
        searchRequest.source(sourceBuilder);

        //执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<Object> list = new LinkedList<>();
        SearchHits hits = searchResponse.getHits();
        Long totalHits = hits.getTotalHits().value;//总条数
        Iterator<SearchHit> iterator = hits.iterator();
        while (iterator.hasNext()) {
            SearchHit searchHit = iterator.next();
            Map<String, Object> data = searchHit.getSourceAsMap();
            list.add(data);
        }

        EsLogPage page = new EsLogPage();
        page.setTotal(totalHits);
        page.setHits(list);
        page.setFrom(req.getFrom());
        return page;
    }

    /**
     * 通用条件
     *
     * @param req
     * @return
     */
    private SearchSourceBuilder addCondition(EsLogReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        if (req != null) {
            if (!StringUtils.isEmpty(req.getApplicationName())) {  //应用的名字
                sourceBuilder.query(QueryBuilders.termsQuery("application_name", req.getApplicationName()));
            }

            if (!StringUtils.isEmpty(req.getStartTime()) || !StringUtils.isEmpty(req.getEndTime())) {  //时间范围锁定
                sourceBuilder.query(QueryBuilders.rangeQuery("timestamp").from(req.getStartTime()).to(req.getEndTime()));
            }

            if (!StringUtils.isEmpty(req.getClasspath())) {
                sourceBuilder.query(QueryBuilders.matchQuery("classpath", req.getClasspath()));
            }

            if (!StringUtils.isEmpty(req.getLevel())) {
                sourceBuilder.query(QueryBuilders.termsQuery("level", req.getLevel()));
            }

            if (!StringUtils.isEmpty(req.getLogContent())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.matchQuery("log_content", req.getLogContent()));
            }

            if (!StringUtils.isEmpty(req.getSessionId())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("session_id", req.getSessionId()));
            }

            if (!StringUtils.isEmpty(req.getThread())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("thread", req.getThread()));
            }

            if (!StringUtils.isEmpty(req.getLineNumber())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("line_number", req.getLineNumber()));
            }

            if (!StringUtils.isEmpty(req.getTraceId())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("trace_id", req.getTraceId()));
            }

            if (!StringUtils.isEmpty(req.getSpanId())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("span_id", req.getSpanId()));
            }

            if (!StringUtils.isEmpty(req.getRequestId())) {  //模糊查找
                sourceBuilder.query(QueryBuilders.fuzzyQuery("request_id", req.getRequestId()));
            }
        }
        return sourceBuilder;
    }
}
